package memory

import (
	"gitee.com/pearl-zz/go-manage-system-core/config/source"
	"github.com/google/uuid"
	"sync"
	"time"
)

type memory struct {
	sync.RWMutex
	ChangeSet *source.ChangeSet
	Watchers  map[string]*watcher
}

func NewSource(opts ...source.Option) source.Source {
	var options source.Options
	for _, o := range opts {
		o(&options)
	}

	m := &memory{Watchers: make(map[string]*watcher)}
	if options.Context != nil {
		c, ok := options.Context.Value(changeSetKey{}).(*source.ChangeSet)
		if ok {
			err := m.Write(c)
			if err != nil {
				return nil
			}
		}
	}
	return m
}

func (m *memory) Read() (*source.ChangeSet, error) {
	m.RLock()
	cs := &source.ChangeSet{
		Data:      m.ChangeSet.Data,
		CheckSum:  m.ChangeSet.CheckSum,
		Format:    m.ChangeSet.Format,
		Source:    m.ChangeSet.Source,
		Timestamp: m.ChangeSet.Timestamp,
	}
	m.RUnlock()
	return cs, nil
}

func (m *memory) Write(c *source.ChangeSet) error {
	if c == nil {
		return nil
	}

	m.Lock()
	m.ChangeSet = &source.ChangeSet{
		Data:      c.Data,
		Format:    c.Format,
		Source:    "memory",
		Timestamp: time.Now(),
	}
	m.ChangeSet.CheckSum = m.ChangeSet.Sum()

	for _, w := range m.Watchers {
		select {
		case w.Updates <- m.ChangeSet:
		default:
		}
	}
	m.Unlock()
	return nil
}

func (m *memory) Watch() (source.Watcher, error) {
	w := &watcher{
		Id:      uuid.New().String(),
		Updates: make(chan *source.ChangeSet, 100),
		Source:  m,
	}
	m.Lock()
	m.Watchers[w.Id] = w
	m.Unlock()
	return w, nil
}

func (m *memory) String() string {
	return "memory"
}
